package com.draven.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.draven.common.BusinessException;
import com.draven.entity.FinanceRecord;
import com.draven.mapper.FinanceRecordMapper;
import com.draven.service.FinanceRecordService;
import com.draven.vo.FinanceStatVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 收支记录服务实现类
 */
@Service
public class FinanceRecordServiceImpl extends ServiceImpl<FinanceRecordMapper, FinanceRecord> implements FinanceRecordService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long add(Long userId, Integer type, BigDecimal amount, String category, Date recordTime, String remark) {
        // 校验类型
        if (type != 1 && type != 2) {
            throw new BusinessException(400, "类型错误");
        }

        // 创建收支记录
        FinanceRecord financeRecord = new FinanceRecord();
        financeRecord.setUserId(userId);
        financeRecord.setType(type);
        financeRecord.setAmount(amount);
        financeRecord.setCategory(category);
        financeRecord.setRecordTime(recordTime);
        financeRecord.setRemark(remark);

        save(financeRecord);
        return financeRecord.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, Long userId, Integer type, BigDecimal amount, String category, Date recordTime, String remark) {
        // 校验类型
        if (type != 1 && type != 2) {
            throw new BusinessException(400, "类型错误");
        }

        // 查询收支记录
        FinanceRecord financeRecord = getDetail(id, userId);

        // 更新信息
        financeRecord.setType(type);
        financeRecord.setAmount(amount);
        financeRecord.setCategory(category);
        financeRecord.setRecordTime(recordTime);
        financeRecord.setRemark(remark);

        updateById(financeRecord);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id, Long userId) {
        // 查询收支记录
        FinanceRecord financeRecord = getDetail(id, userId);

        // 删除收支记录
        removeById(id);
    }

    @Override
    public FinanceRecord getDetail(Long id, Long userId) {
        // 查询收支记录
        FinanceRecord financeRecord = getById(id);
        if (financeRecord == null) {
            throw new BusinessException(400, "收支记录不存在");
        }

        // 校验所有权
        if (!financeRecord.getUserId().equals(userId)) {
            throw new BusinessException(403, "无权限操作");
        }

        return financeRecord;
    }

    @Override
    public Page<FinanceRecord> page(Long userId, Integer type, String category, Date startTime, Date endTime, Integer pageNum, Integer pageSize) {
        // 构建查询条件
        LambdaQueryWrapper<FinanceRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FinanceRecord::getUserId, userId);
        wrapper.eq(type != null, FinanceRecord::getType, type);
        wrapper.eq(StringUtils.isNotBlank(category), FinanceRecord::getCategory, category);
        wrapper.ge(startTime != null, FinanceRecord::getRecordTime, startTime);
        wrapper.le(endTime != null, FinanceRecord::getRecordTime, endTime);
        wrapper.orderByDesc(FinanceRecord::getRecordTime);

        // 分页查询
        return page(new Page<>(pageNum, pageSize), wrapper);
    }

    @Override
    public FinanceStatVO stat(Long userId, Date startTime, Date endTime) {
        // 构建查询条件
        LambdaQueryWrapper<FinanceRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FinanceRecord::getUserId, userId);
        wrapper.ge(startTime != null, FinanceRecord::getRecordTime, startTime);
        wrapper.le(endTime != null, FinanceRecord::getRecordTime, endTime);

        // 查询所有收支记录
        List<FinanceRecord> records = list(wrapper);

        // 统计收入和支出
        BigDecimal totalIncome = BigDecimal.ZERO;
        BigDecimal totalExpense = BigDecimal.ZERO;

        // 按类型和分类统计
        Map<String, BigDecimal> incomeMap = new HashMap<>();
        Map<String, BigDecimal> expenseMap = new HashMap<>();

        for (FinanceRecord record : records) {
            if (record.getType() == 1) {
                // 收入
                totalIncome = totalIncome.add(record.getAmount());
                // 按分类统计
                String category = StringUtils.isBlank(record.getCategory()) ? "其他" : record.getCategory();
                incomeMap.put(category, incomeMap.getOrDefault(category, BigDecimal.ZERO).add(record.getAmount()));
            } else if (record.getType() == 2) {
                // 支出
                totalExpense = totalExpense.add(record.getAmount());
                // 按分类统计
                String category = StringUtils.isBlank(record.getCategory()) ? "其他" : record.getCategory();
                expenseMap.put(category, expenseMap.getOrDefault(category, BigDecimal.ZERO).add(record.getAmount()));
            }
        }

        // 计算收入分类占比
        List<FinanceStatVO.CategoryStat> incomeStats = calculateCategoryStats(incomeMap, totalIncome);

        // 计算支出分类占比
        List<FinanceStatVO.CategoryStat> expenseStats = calculateCategoryStats(expenseMap, totalExpense);

        // 计算收支结余
        BigDecimal balance = totalIncome.subtract(totalExpense);

        return new FinanceStatVO(totalIncome, totalExpense, balance, incomeStats, expenseStats);
    }

    @Override
    public List<FinanceStatVO.CategoryStat> statByCategory(Long userId, Integer type, Date startTime, Date endTime) {
        // 构建查询条件
        LambdaQueryWrapper<FinanceRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FinanceRecord::getUserId, userId);
        wrapper.eq(type != null, FinanceRecord::getType, type);
        wrapper.ge(startTime != null, FinanceRecord::getRecordTime, startTime);
        wrapper.le(endTime != null, FinanceRecord::getRecordTime, endTime);

        // 查询所有收支记录
        List<FinanceRecord> records = list(wrapper);

        // 按分类统计
        Map<String, BigDecimal> categoryMap = new HashMap<>();
        BigDecimal total = BigDecimal.ZERO;

        for (FinanceRecord record : records) {
            total = total.add(record.getAmount());
            String category = StringUtils.isBlank(record.getCategory()) ? "其他" : record.getCategory();
            categoryMap.put(category, categoryMap.getOrDefault(category, BigDecimal.ZERO).add(record.getAmount()));
        }

        // 计算分类占比
        return calculateCategoryStats(categoryMap, total);
    }

    /**
     * 计算分类统计
     *
     * @param categoryMap 分类金额映射
     * @param total       总金额
     * @return 分类统计列表
     */
    private List<FinanceStatVO.CategoryStat> calculateCategoryStats(Map<String, BigDecimal> categoryMap, BigDecimal total) {
        if (total.compareTo(BigDecimal.ZERO) == 0) {
            return categoryMap.entrySet().stream()
                    .map(entry -> new FinanceStatVO.CategoryStat(entry.getKey(), entry.getValue(), BigDecimal.ZERO))
                    .collect(Collectors.toList());
        }

        return categoryMap.entrySet().stream()
                .map(entry -> {
                    BigDecimal percentage = entry.getValue()
                            .divide(total, 4, RoundingMode.HALF_UP)
                            .multiply(new BigDecimal("100"))
                            .setScale(2, RoundingMode.HALF_UP);
                    return new FinanceStatVO.CategoryStat(entry.getKey(), entry.getValue(), percentage);
                })
                .sorted((o1, o2) -> o2.getAmount().compareTo(o1.getAmount()))
                .collect(Collectors.toList());
    }
} 